<?php
namespace modules;
use \modules\auth\api as auth_api;
use \phiction\exceptions\access_control;
use \phiction\array_utils as arr;
use \phiction\iterator_utils as iter;

class ui
{
    // $controls = [
    //      [ string `text`, string `link` = 'javascript:', ... ]
    // ]
    static function header_control($html, array $controls)
    {
        return $html->mark(['div',
            'class' => 'header-control',
            self::format_anchor_controls($controls),
        ]);
    }

    static function header_control_or_login($q, $html, &$args, array $authed_controls)
    {
        $shards = auth_api::login_status($q, $args);
        if (is_null($shards)) {
            $controls = [self::login_control()];
        } else {
            $login = $shards['login'];
            $controls = $authed_controls;
            $controls[] = [self::icon_label($login, 'user'), '/auth/profile'];
            $controls[] = [self::icon_label('登出', 'sign-out'), 'class' => 'logout'];
        }
        return self::header_control($html, $controls);
    }

    static function login_control()
    {
        return [self::icon_label('登录', 'sign-in'), '?throw=login'];
    }

    static function form($html, string $api, $submit_element, array $fields, array $controls=[], $redirect=null)
    {
        return $html->mark(['form',
            'action' => $api,
            'method' => 'post',
            'data-redirect' => $redirect,

            self::format_fields(['.'], $fields),

            ['div', 'class' => 'form-controls',
                ['div', 'class' => 'form-error'],
                self::format_anchor_controls($controls),
                ['button', $submit_element],
            ],
        ]);
    }

    static function icon(string $title, string ...$names)
    {
        $fa_names = implode(' ', array_map(function ($name) {
            return "fa-$name";
        }, $names));
        $class = "fa $fa_names";
        return ['span', 'class' => $class, 'title' => $title, 'aria-hidden' => true];
    }

    static function icon_label(string $label, string ...$names)
    {
        return ['.',
            self::icon($label, ...$names),
            ['span', $label, 'class' => 'icon-label'],
        ];
    }

    static function card($title, $content, array $controls=[])
    {
        return ['div',
            'class' => 'card',
            ['div',
                'class' => 'card-header',
                ['div', 'class' => 'card-title', $title],
                ['div',
                    'class' => 'card-controls',
                    self::format_anchor_controls($controls),
                ],
            ],
            ['div', 'class' => 'card-body', $content],
        ];
    }

    static function pager(callable $page_link, int $page, bool $has_next)
    {
        $pager = ['div', 'class' => 'pager'];
        if ($page > 1) $pager[] = [ 'a', 'href' => $page_link($page-1), "上一页" ];
        else $pager[] = [ 'a', 'class' => 'disabled', "上一页" ];
        if ($page < 1 || $has_next) $pager[] = [ 'a', 'href' => $page_link($page+1), "下一页" ];
        else $pager[] = [ 'a', 'class' => 'disabled', "下一页" ];
        return $pager;
    }


    #######################################################################
    # formats

    static function format_anchor_controls(array $controls)
    {
        return self::format_controls(
            ['.'], $controls, ['a'],
            1, ['href', 'javascript:']);
    }

    static function format_controls(array $initial, array $controls, array $initial_per_control, ...$ordered)
    {
        // desugar $ordered
        foreach ($ordered as &$expect) {
            if (is_int($expect) || is_string($expect)) {
                $expect = [$expect, null];
            }
            else if (is_array($expect)) {
                $num = count($expect);
                if ($num < 1) throw new \InvalidArgumentException("array must have at least 1 element");
                if ($num > 2) throw new \InvalidArgumentException("array can only have at most 2 elements");
                if ($num === 1) $expect[] = null;
            }
            else {
                throw new \InvalidArgumentException("only support int, string and/or array");
            }
        }

        foreach ($controls as $control) {
            $initial[] = self::format_control($initial_per_control, $control, $ordered);
        }

        return $initial;
    }

    private static function format_control(array $initial, array $control, array $sugarfree_ordered)
    {
        foreach ($sugarfree_ordered as $i => $expect) {
            $initial[$expect[0]] = arr::get_or($control, $i, $expect[1]);
        }

        foreach (iter::str_keyed($control) as $key => $value) {
            $initial[$key] = $value;
        }

        return $initial;
    }

    static function format_fields(array $initial, array $fields)
    {
        foreach ($fields as $field)
            $initial[] = self::format_field($field);
        return $initial;
    }

    static function format_field(array $field)
    {
        $name = arr::get_or_bad_request($field, 0);
        $type = arr::get_or_bad_request($field, 1);
        $placeholder = arr::get_or_bad_request($field, 2);
        $value = arr::get_or_null($field, 3);

        if ($type === 'textarea') {
            $result = [$type,
                'name' => $name,
                'placeholder' => $placeholder,
                $value,
            ];
        }

        elseif ($type === 'hidden') {
            $result = ['/input',
                'name' => $name,
                'type' => $type,
                'value' => $placeholder,    // this is not a typo, the value IS placeholder
            ];
        }

        else {
            $result = ['/input',
                'name' => $name,
                'type' => $type,
                'placeholder' => $placeholder,
                'value' => $value,
            ];
        }

        $result['required'] = true;
        return iter::fuse_str_keyed($result, $field);
    }
}

